#ifndef PRVP_EVALUATOR_HPP_
#define PRVP_EVALUATOR_HPP_

//#include <cmath>
#include <stdlib.h>
#include <math.h>

#include "../OptFrame/Evaluation.hpp"
#include "../OptFrame/Evaluator.hpp"

#include "Representation.h"
#include "Memory.h"
#include "Solution.h"
#include "Evaluation.h"

#include "ProblemInstance.hpp"

#define EPSILON_PRVP 0.0001

class PRVPEvaluator: public Evaluator<RepPRVP, MemPRVP>
{
private:
	PRVPProblemInstance& pPRVP;

	// Your private vars

public:
	PRVPEvaluator(PRVPProblemInstance& _pPRVP) : // If necessary, add more parameters
		pPRVP(_pPRVP)
	{
		// Put the rest of your code here
	}

	virtual ~PRVPEvaluator()
	{
	}

	EvaluationPRVP& evaluate(const RepPRVP& rep)
	{
		//contando mais uma avaliação total feita
		aval++;

		double fo = 0; // Evaluation Function Value
		double inf = 0;

		MemPRVP mem(pPRVP.nCli + 1, pPRVP.nPeriod);//contando o depósito

		for (int p = 0; p < rep.size(); p++) //periodos
		{

			int veiculos = rep.at(p).size();
			vector<double> aux_load(veiculos);
			for (int v = 0; v < veiculos; v++) //veiculos
			{
				int clientes = rep.at(p).at(v).size();
				if (clientes > 0)
				{
					double demanda_atendida = 0;
					fo += (*pPRVP.dist)(0, rep.at(p).at(v).at(0));

					for (int c = 0; c < clientes - 1; c++)
					{
						demanda_atendida += pPRVP.dados->at(rep.at(p).at(v).at(c)).at(DEMANDA);
						fo += (*pPRVP.dist)(rep.at(p).at(v).at(c), rep.at(p).at(v).at(c + 1));
					}
					fo += (*pPRVP.dist)(rep.at(p).at(v).at(clientes - 1), 0);
					demanda_atendida += pPRVP.dados->at(rep.at(p).at(v).back()).at(DEMANDA);

					//load para a memoria
					aux_load.at(v) = demanda_atendida;

					inf += max(demanda_atendida - pPRVP.capacidade, 0.0);
					//cout<<"demanda "<<demanda_atendida<<" cap:"<<pPRVP.capacidade<<" \tinf:"<<inf<<endl;
				}
				else
					aux_load.at(v) = 0;
			}

			mem.getLoad().at(p) = aux_load;

		}

		for (int p = 0; p < rep.size(); p++) //periodos
		{
			int veiculos = rep.at(p).size();

			for (int v = 0; v < veiculos; v++) //veiculos
			{

				int clientes = rep.at(p).at(v).size();
				if (clientes > 0)
				{
					for (int c = 0; c < clientes; c++)
					{
						mem.getLocal_cli().at(rep.at(p).at(v).at(c)).push_back(p);
					}
				}
			}
		}

		//cout<<"%%%%inf:"<<inf<<endl;
		return *new EvaluationPRVP(fo, inf * 10000, mem);
		//return *new EvaluationPRVP(fo, inf*10, mem);
		//return *new EvaluationPRVP(fo, *new int);
	}

	void evaluate(EvaluationPRVP& ev, const RepPRVP& rep)
	{

		//retirando a memória da avaliacao
		ADS& ads = ev.getM();

		double fo = 0; // Evaluation Function Value
		double inf = 0;
		double pesoCapacidade = 10000;
		if (ads.getDelta() != 0 || ads.getDelta_inf() != 0)
		{
			//contando mais uma avaliação rápida feita
			avalrap++;
			//cout<<"avaliacao rapida: "<<ev.getObjFunction()<< " + "<<ads.getDelta()<< "= "<<ev.getObjFunction() + ads.getDelta()<<endl;
			//cout<<"avaliacao rapida inf: "<<ev.getInfMeasure()<< " + "<<ads.getDelta_inf()<< "= "<<ev.getInfMeasure() + ads.getDelta_inf()<<endl;
			//getchar();
			fo = ev.getObjFunction() + ads.getDelta();
			inf = ev.getInfMeasure() + ads.getDelta_inf() * pesoCapacidade;
		}
		else
		{
			//contando mais uma avaliação total feita
			aval++;
			for (int p = 0; p < rep.size(); p++) //periodos
			{
				int veiculos = rep.at(p).size();
				vector<double> aux_load(veiculos);
				for (int v = 0; v < veiculos; v++) //veiculos
				{
					//if (ads.getStatus().at(p).at(v) == 0)
					//{
					int clientes = rep.at(p).at(v).size();
					if (clientes > 0)
					{
						double demanda_atendida = 0;
						fo += (*pPRVP.dist)(0, rep.at(p).at(v).at(0));

						for (int c = 0; c < clientes - 1; c++)
						{
							demanda_atendida += pPRVP.dados->at(rep.at(p).at(v).at(c)).at(DEMANDA);
							fo += (*pPRVP.dist)(rep.at(p).at(v).at(c), rep.at(p).at(v).at(c + 1));
						}
						fo += (*pPRVP.dist)(rep.at(p).at(v).at(clientes - 1), 0);
						demanda_atendida += pPRVP.dados->at(rep.at(p).at(v).back()).at(DEMANDA);

						//memoriai
						aux_load.at(v) = demanda_atendida;

						inf += max(demanda_atendida - pPRVP.capacidade, 0.0);
						//cout<<"demanda "<<demanda_atendida<<" cap:"<<pPRVP.capacidade<<" \tinf:"<<inf<<endl;
					}
					else
						aux_load.at(v) = 0;
					//}
				}

				ads.getLoad().at(p) = aux_load;
			}

			inf *= pesoCapacidade;
		}

		ads.setDelta(0.0);
		ads.setDelta_inf(0.0);

		ev.setObjFunction(fo);
		ev.setInfMeasure(inf);
	}

	virtual bool betterThan(double a, double b)
	{
		// MINIMIZATION
		return (a < (b - EPSILON_PRVP));
	}

};

#endif /*PRVP_EVALUATOR_HPP_*/

